﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.Diagnostics;
using System.IO;

namespace libReadWrite
{
    /// <summary>
    /// Utilities for sockets
    /// </summary>
    class SocketController
    {
        public static void Send(Socket socket, byte[] buffer, int offset, int size, int timeout)
        {
            try
            {
                int startTickCount = Environment.TickCount;
                int sent = 0;  // how many bytes is already sent
                do
                {
                    if (Environment.TickCount > startTickCount + timeout)
                        throw new Exception("Timeout.");
                    try
                    {
                        sent += socket.Send(buffer, offset + sent, size - sent, SocketFlags.None);
                    }
                    catch (SocketException ex)
                    {
                        if (ex.SocketErrorCode == SocketError.WouldBlock ||
                            ex.SocketErrorCode == SocketError.IOPending ||
                            ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
                        {
                            // socket buffer is probably full, wait and try again
                            Thread.Sleep(30);
                        }
                        else
                        {
                            throw ex;  // any serious error occurr
                        }
                    }
                } while (sent < size);
            }
            catch (Exception ex)
            {
                System.Console.WriteLine(ex.Message);
                throw ex;
            }
        }

        public static void Receive(Socket socket, byte[] buffer, int offset, int size, int timeout)
        {
            int startTickCount = Environment.TickCount;
            int received = 0;  // how many bytes is already received
            do
            {
                if (Environment.TickCount > startTickCount + timeout)
                    throw new Exception("Timeout.");
                try
                {
                    received += socket.Receive(buffer, offset + received, size - received, SocketFlags.None);
                }
                catch (SocketException ex)
                {
                    if (ex.SocketErrorCode == SocketError.WouldBlock ||
                        ex.SocketErrorCode == SocketError.IOPending ||
                        ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
                    {
                        // socket buffer is probably empty, wait and try again
                        Thread.Sleep(30);
                    }
                    else
                        throw ex;  // any serious error occurr
                }
            } while (received < size);
        }

        //  size phai la so nguyen duong 
        public static void Receive(Socket socket, byte[] buffer, int offset, int size)
        {
            int received = 0;  // how many bytes is already received
            
            do
            {
                if (socket.Connected == false)
                    throw new IOException();

                try
                {
                    int nbytes = socket.Receive(buffer, offset + received, size - received, SocketFlags.None);

                    if (nbytes == 0)
                    {
                        // socket buffer is probably empty, wait and try again
                        Thread.Sleep(30);
                    }
                    else{
                        received += nbytes;
                    }
                }
                catch (SocketException ex)
                {
                    if (ex.SocketErrorCode == SocketError.WouldBlock ||
                        ex.SocketErrorCode == SocketError.IOPending ||
                        ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
                    {
                        // socket buffer is probably empty, wait and try again
                        Thread.Sleep(30);
                    }
                    else
                    {
                        throw ex;  // any serious error occurr
                    }
                }
            } while (received < size);
        }

        public static String ReadStringFromSocket(Socket s)
        {
            byte[] nbytes = new byte[4];
            SocketController.Receive(s, nbytes, 0, 4);

            //Bên client gửi big-endian
            int n = (nbytes[0] << 24) + (nbytes[1] << 16) + (nbytes[2] << 8) + (nbytes[3] << 0);

            if (n != 0)
            {
                byte[] buffer = new byte[n];
                SocketController.Receive(s, buffer, 0, n);

                String str = System.Text.Encoding.Unicode.GetString(buffer);

                return str;
            }
            else
            {
                return "";
            }
        }

        public static void WriteStringToSocket(Socket s, string str)
        {
            int nlength = str.Length;

            if (nlength == 0)
            {
                WriteInt(s, nlength);
            }
            else if (nlength > 0)
            {
                byte[] unicode = System.Text.Encoding.Unicode.GetBytes(str);
                
                int nbytes = unicode.Length;
                WriteInt(s, nbytes);

                SocketController.Send(s, unicode, 0, nbytes, 10000);
            }

        }

        public static void WriteByte(Socket s, byte b)
        {
            byte[] buffer = new byte[1];
            buffer[0] = b;
            SocketController.Send(s, buffer, 0, 1, 10000);
        }

        public static void WriteInt(Socket s, int n)
        {
            //BigEndian

            byte[] buffer = new byte[4];
           
            buffer[0] = (byte)(n << 0   >> 24);
            buffer[1] = (byte)(n << 8   >> 24);
            buffer[2] = (byte)(n << 16  >> 24);
            buffer[3] = (byte)(n << 24  >> 24);

            SocketController.Send(s, buffer, 0, 4, 10000);
        }
    }
}
